/**************************************************************************//**
 * @file     FlashPrg.c
 * @brief    Flash Programming Functions adapted for New Device Flash
 * @version  V1.0.0
 * @date     10. January 2018
 ******************************************************************************/
/*
 * Copyright (c) 2010-2018 Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the License); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include ".\FlashOS.H"        // FlashOS Structures
#include "fsl_common.h"
#include "fsl_cache.h"
#include "board.h"
#include "pin_mux.h"
#include "flash_def.h"
#include "stdlib.h"
#include "time.h"
#include "fsl_lpuart.h"
#include "stdio.h"

#include "fsl_common.h"
#include "fsl_iomuxc.h"
#include "pin_mux.h"
#define NAND_FLASH_START (EXAMPLE_FLEXSPI_AMBA_BASE+0x2000000) 

extern void flexspi_nand_flash_init(FLEXSPI_Type *base);
extern status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base);
extern status_t flexspi_nor_erase_chip(FLEXSPI_Type *base);
extern status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address);
extern status_t flexspi_nor_flash_erase_block(FLEXSPI_Type *base, uint32_t address);
extern status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src);

SDK_ALIGN(static uint8_t s_nand_program_buffer[2048], 4);
/*
 * void DCACHE_InvalidateByRange(uint32_t address, uint32_t size_byte)
 * 无效化Cache中的数据
 * 如果内存中的数据被DMA更改，CPU读取数据之前要无效化Cache，这样CPU在Cache中找不到数据备份则会直接从内存中
 * 读取。函数DCACHE_InvalidateByRange用于设置无效化Cache中的数据。
 */

/* 
   Mandatory Flash Programming Functions (Called by FlashOS):
                int Init        (unsigned long adr,   // Initialize Flash
                                 unsigned long clk,
                                 unsigned long fnc);
                int UnInit      (unsigned long fnc);  // De-initialize Flash
                int EraseSector (unsigned long adr);  // Erase Sector Function
                int ProgramPage (unsigned long adr,   // Program Page Function
                                 unsigned long sz,
                                 unsigned char *buf);

   Optional  Flash Programming Functions (Called by FlashOS):
                int BlankCheck  (unsigned long adr,   // Blank Check
                                 unsigned long sz,
                                 unsigned char pat);
                int EraseChip   (void);               // Erase complete Device
      unsigned long Verify      (unsigned long adr,   // Verify Function
                                 unsigned long sz,
                                 unsigned char *buf);

       - BlanckCheck  is necessary if Flash space is not mapped into CPU memory space
       - Verify       is necessary if Flash space is not mapped into CPU memory space
       - if EraseChip is not provided than EraseSector for all sectors is called
*/

uint8_t txbuff[]   = "Lpuart polling example\r\nBoard will send back received characters\r\n";
int fputc(int ch,FILE *f)
{
    LPUART_WriteBlocking(LPUART1, (uint8_t *)&ch, 1);
    return ch;
}
void uart_init(void)
{
    lpuart_config_t config;

    
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_12_LPUART1_TXD, 0U); 
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_13_LPUART1_RXD, 0U); 
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_12_LPUART1_TXD, 0x10B0U); 
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_13_LPUART1_RXD, 0x10B0U); 
    
    LPUART_GetDefaultConfig(&config);
    config.baudRate_Bps = BOARD_DEBUG_UART_BAUDRATE;
    config.enableTx     = true;
    config.enableRx     = true;

    LPUART_Init(LPUART1, &config, BOARD_DebugConsoleSrcFreq());
}
/*
 *  Initialize Flash Programming Functions
 *    Parameter:      adr:  Device Base Address
 *                    clk:  Clock Frequency (Hz)
 *                    fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */
//SDK_ALIGN(static uint8_t s_nand_program_buffer[2112], 4);
int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {
    /* Add your Code */
    status_t status;
    uint8_t regStatus = 0;
    lpuart_config_t config;
    BOARD_ConfigMPU();
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
    if(fnc == 1)
    {
        uart_init();
        printf("init\r\n");
        flexspi_flash_port_init(EXAMPLE_FLEXSPI,NAND_FLASH_PORT);/* 初始化FLEXSPI基础参数 */
    
        status = flexspi_nand_get_status(EXAMPLE_FLEXSPI, 0xC0, &regStatus);
        
        status = flexspi_nand_get_status(EXAMPLE_FLEXSPI, 0xA0, &regStatus);
        status = flexspi_nand_set_status(EXAMPLE_FLEXSPI, 0xA0, 0);
        status = flexspi_nand_get_status(EXAMPLE_FLEXSPI, 0xA0, &regStatus);
        
        status = flexspi_nand_flash_erase_sector(EXAMPLE_FLEXSPI, (0<<6));
        status = flexspi_nand_flash_erase_sector(EXAMPLE_FLEXSPI, (1<<6));
        status = flexspi_nand_flash_erase_sector(EXAMPLE_FLEXSPI, (2<<6));
        
//        flexspi_flash_port_init(EXAMPLE_FLEXSPI,NOR_FLASH_PORT);
//        status = flexspi_nor_enable_quad_mode(EXAMPLE_FLEXSPI);
//        if (status != kStatus_Success)
//        {
//            return status;
//        }
    }
    return (0);                                  // Finished without Errors
}


/*
 *  De-Initialize Flash Programming Functions
 *    Parameter:      fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */
int UnInit (unsigned long fnc) {

  /* Add your Code */
  return (0);                                  // Finished without Errors
}


/*
 *  Erase complete Flash Memory
 *    Return Value:   0 - OK,  1 - Failed
 */
int EraseChip (void) {
    /* Add your Code */
    status_t status;

//    flexspi_flash_port_init(EXAMPLE_FLEXSPI,NOR_FLASH_PORT);
//    status = flexspi_nor_erase_chip(EXAMPLE_FLEXSPI);/* 这里只全片擦除nor */
//    if (status != kStatus_Success)
//    {
//        return (1);
//    }

    DCACHE_InvalidateByRange(EXAMPLE_FLEXSPI_AMBA_BASE, 0x8000); // 32KB    0x400000

    return (0);                                  // Finished without Errors
}


/*
 *  Erase Sector in Flash Memory
 *    Parameter:      adr:  Sector Address
 *    Return Value:   0 - OK,  1 - Failed
 */
/* Nor最小可以擦除一个sector，大小为4K，但是NAND最小只能擦除一个BLOCK，大小为64*2KB = 128KB，
差距巨大，现在不在这个函数擦，在写入函数的地方，进行对应的擦除，本函数只保留nor的一个sector擦除*/
/*
 *  Erase Sector in Flash Memory
 *    Parameter:      adr:  Sector Address
 *    Return Value:   0 - OK,  1 - Failed
 */
int EraseSector (unsigned long adr) {
    /* Add your Code */
    status_t status;

#if SECTOR_SIZE == 0x1000
//    status = flexspi_nor_flash_erase_sector(EXAMPLE_FLEXSPI, (adr - EXAMPLE_FLEXSPI_AMBA_BASE));
//    if (status != kStatus_Success)
//    {
//        return (1);
//    }
#elif SECTOR_SIZE == 0x10000 /* 64K */
    status = flexspi_nor_flash_erase_block(EXAMPLE_FLEXSPI, (adr - EXAMPLE_FLEXSPI_AMBA_BASE));
    if (status != kStatus_Success)
    {
        return (1);
    }
#endif

    DCACHE_InvalidateByRange(adr, SECTOR_SIZE);

    return (0);                                  // Finished without Errors
}


/*
 *  Program Page in Flash Memory
 *    Parameter:      adr:  Page Start Address
 *                    sz:   Page Size
 *                    buf:  Page Data
 *    Return Value:   0 - OK,  1 - Failed
 */
int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {
    /* Add your Code */
    status_t status;
    volatile static int Erase_block = 1;/* 上一次擦除的block */
    uint32_t write_block = 0;
    uint32_t write_page  = 0;
    
    uart_init();
    
    flexspi_flash_port_init(EXAMPLE_FLEXSPI,NAND_FLASH_PORT);
    
    write_block = (adr - NAND_FLASH_START)/(64*2048);
    if(write_block>(Erase_block - 1))
    {
        Erase_block = Erase_block + 1;
        flexspi_nand_flash_erase_sector(EXAMPLE_FLEXSPI,(Erase_block - 1)<<6);
    }
    write_page = ((adr - NAND_FLASH_START)%(64*2048)) / 2048;
    
    flexspi_nand_flash_page_program(EXAMPLE_FLEXSPI, (write_block<<6)+write_page,(uint32_t*)buf);
    
    return (0);                                  // Finished without Errors
}

#if 0 /* 校验函数不是必须的 */
///*
// *  Blank Check Checks if Memory is Blank
// *    Parameter:      adr:  Block Start Address
// *                    sz:   Block Size (in bytes)
// *                    pat:  Block Pattern
// *    Return Value:   0 - OK,  1 - Failed
// */
//int BlankCheck (unsigned long adr, unsigned long sz, unsigned char pat) {
//    /* Add your Code */
//    
//    return (1);                                        // Always Force Erase
//}


/*可选，若未做校验函数，那么MDK会读取数据做CRC校验 */
///*  
// *  Verify Flash Contents
// *    Parameter:      adr:  Start Address
// *                    sz:   Size (in bytes)
// *                    buf:  Data
// *    Return Value:   (adr+sz) - OK, Failed Address
// */
//unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf) {
//    /* Add your Code */
//    

//    return (0);
//}
#endif